{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Goodies of the [Python Standard Library](https://docs.python.org/3/library/#the-python-standard-library)\n",
    "The Python Standard Libary is part of your Python installation. It contains a wide range of packages which may be helpful while building your Python masterpieces. This notebook lists some of the commonly used packages and their main functionalities."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [`datetime`](https://docs.python.org/3/library/datetime.html#module-datetime) for working with dates and times"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import datetime as dt\n",
    "\n",
    "local_now = dt.datetime.now()\n",
    "print('local now: {}'.format(local_now))\n",
    "\n",
    "utc_now = dt.datetime.utcnow()\n",
    "print('utc now: {}'.format(utc_now))\n",
    "\n",
    "# You can access any value separately:\n",
    "print('{} {} {} {} {} {}'.format(local_now.year, local_now.month,\n",
    "                                 local_now.day, local_now.hour,\n",
    "                                 local_now.minute, local_now.second))\n",
    "\n",
    "print('date: {}'.format(local_now.date()))\n",
    "print('time: {}'.format(local_now.time()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `strftime()`\n",
    "For string formatting the `datetime`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "formatted1 = local_now.strftime('%Y/%m/%d-%H:%M:%S')\n",
    "print(formatted1)\n",
    "\n",
    "formatted2 = local_now.strftime('date: %Y-%m-%d time:%H:%M:%S')\n",
    "print(formatted2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `strptime()`\n",
    "For converting a datetime string into a `datetime` object "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_dt = dt.datetime.strptime('2000-01-01 10:00:00', '%Y-%m-%d %H:%M:%S')\n",
    "print('my_dt: {}'.format(my_dt))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [`timedelta`](https://docs.python.org/3/library/datetime.html#timedelta-objects)\n",
    "For working with time difference."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tomorrow = local_now + dt.timedelta(days=1)\n",
    "print('tomorrow this time: {}'.format(tomorrow))\n",
    "\n",
    "delta = tomorrow - local_now\n",
    "print('tomorrow - now = {}'.format(delta))\n",
    "print('days: {}, seconds: {}'.format(delta.days, delta.seconds))\n",
    "print('total seconds: {}'.format(delta.total_seconds()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Working with timezones\n",
    "Let's first make sure [`pytz`](http://pytz.sourceforge.net/) is installed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "!{sys.executable} -m pip install pytz"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import datetime as dt\n",
    "import pytz\n",
    "\n",
    "naive_utc_now = dt.datetime.utcnow()\n",
    "print('naive utc now: {}, tzinfo: {}'.format(naive_utc_now, naive_utc_now.tzinfo))\n",
    "\n",
    "# Localizing naive datetimes\n",
    "UTC_TZ = pytz.timezone('UTC')\n",
    "utc_now = UTC_TZ.localize(naive_utc_now)\n",
    "print('utc now: {}, tzinfo: {}'.format(utc_now, utc_now.tzinfo))\n",
    "\n",
    "# Converting localized datetimes to different timezone\n",
    "PARIS_TZ = pytz.timezone('Europe/Paris')\n",
    "paris_now = PARIS_TZ.normalize(utc_now)\n",
    "print('Paris: {}, tzinfo: {}'.format(paris_now, paris_now.tzinfo))\n",
    "\n",
    "NEW_YORK_TZ = pytz.timezone('America/New_York')\n",
    "ny_now = NEW_YORK_TZ.normalize(utc_now)\n",
    "print('New York: {}, tzinfo: {}'.format(ny_now, ny_now.tzinfo))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**NOTE**: If your project uses datetimes heavily, you may want to take a look at external libraries, such as [Pendulum](https://pendulum.eustace.io/docs/) and [Maya](https://github.com/kennethreitz/maya), which make working with datetimes easier for certain use cases."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [`logging`](https://docs.python.org/3/library/logging.html#module-logging)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import logging\n",
    "\n",
    "# Handy way for getting a dedicated logger for every module separately\n",
    "logger = logging.getLogger(__name__)\n",
    "logger.setLevel(logging.WARNING)\n",
    "\n",
    "logger.debug('This is debug')\n",
    "logger.info('This is info')\n",
    "logger.warning('This is warning')\n",
    "logger.error('This is error')\n",
    "logger.critical('This is critical')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Logging expections\n",
    "There's a neat `exception` function in `logging` module which will automatically log the stack trace in addition to user defined log entry. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "try:\n",
    "    path_calculation = 1 / 0\n",
    "except ZeroDivisionError:\n",
    "    logging.exception('All went south in my calculation')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Formatting log entries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import logging\n",
    "\n",
    "# This is only required for Jupyter notebook environment\n",
    "from importlib import reload\n",
    "reload(logging)\n",
    "\n",
    "my_format = '%(asctime)s | %(name)-12s | %(levelname)-10s | %(message)s'\n",
    "logging.basicConfig(format=my_format)\n",
    "\n",
    "logger = logging.getLogger('MyLogger')\n",
    "\n",
    "logger.warning('Something bad is going to happen')\n",
    "logger.error('Uups, it already happened')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Logging to a file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import logging\n",
    "\n",
    "# This is only required for Jupyter notebook environment\n",
    "from importlib import reload\n",
    "reload(logging)\n",
    "\n",
    "logger = logging.getLogger('MyFileLogger')\n",
    "\n",
    "# Let's define a file_handler for our logger\n",
    "log_path = os.path.join(os.getcwd(), 'my_log.txt')\n",
    "file_handler = logging.FileHandler(log_path)\n",
    "\n",
    "# And a nice format\n",
    "formatter = logging.Formatter('%(asctime)s | %(name)-12s | %(levelname)-10s | %(message)s')\n",
    "file_handler.setFormatter(formatter)\n",
    "\n",
    "logger.addHandler(file_handler)\n",
    "\n",
    "# If you want to see it also in the console, add another handler for it\n",
    "# logger.addHandler(logging.StreamHandler())\n",
    "\n",
    "logger.warning('Oops something is going to happen')\n",
    "logger.error('John Doe visits our place')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [`random`](https://docs.python.org/3/library/random.html) for random number generation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random\n",
    "\n",
    "rand_int = random.randint(1, 100)\n",
    "print('random integer between 1-100: {}'.format(rand_int))\n",
    "\n",
    "rand = random.random()\n",
    "print('random float between 0-1: {}'.format(rand))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you need pseudo random numbers, you can set the `seed` for random. This will reproduce the output (try running the cell multiple times):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random\n",
    "\n",
    "random.seed(5)  # Setting the seed\n",
    "\n",
    "# Let's print 10 random numbers\n",
    "for _ in range(10):\n",
    "    print(random.random())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [`re`](https://docs.python.org/3/library/re.html#module-re) for regular expressions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Searching occurences"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import re\n",
    "\n",
    "secret_code = 'qwret 8sfg12f5 fd09f_df'\n",
    "# \"r\" at the beginning means raw format, use it with regular expression patterns\n",
    "search_pattern = r'(g12)' \n",
    "\n",
    "match = re.search(search_pattern, secret_code)\n",
    "print('match: {}'.format(match))\n",
    "print('match.group(): {}'.format(match.group()))\n",
    "\n",
    "numbers_pattern = r'[0-9]'\n",
    "numbers_match = re.findall(numbers_pattern, secret_code)\n",
    "print('numbers: {}'.format(numbers_match))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Variable validation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import re\n",
    "\n",
    "def validate_only_lower_case_letters(to_validate):\n",
    "    pattern = r'^[a-z]+$'\n",
    "    return bool(re.match(pattern, to_validate))\n",
    "\n",
    "print(validate_only_lower_case_letters('thisshouldbeok'))\n",
    "print(validate_only_lower_case_letters('thisshould notbeok'))\n",
    "print(validate_only_lower_case_letters('Thisshouldnotbeok'))\n",
    "print(validate_only_lower_case_letters('thisshouldnotbeok1'))\n",
    "print(validate_only_lower_case_letters(''))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
